package cnsatmsmart.automation.mmi.model;

import cnsatmsmart.automation.mmi.controller.Buffer.FlightPlanList;
import cnsatmsmart.automation.mmi.helper.utilities.GlobalEnvVars;
import cnsatmsmart.automation.mmi.view.layers.AirportsLayer;
import cnsatmsmart.automation.mmi.view.layers.AirwaysLayer;
import cnsatmsmart.automation.mmi.view.layers.ControlLayer;
import cnsatmsmart.automation.mmi.view.layers.FixesLayer;
import cnsatmsmart.automation.mmi.view.layers.FlightLayer;
import cnsatmsmart.automation.mmi.view.layers.RadarLayer;
import com.bbn.openmap.BufferedLayerMapBean;
import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.Layer;
import com.bbn.openmap.LayerHandler;
import com.bbn.openmap.MapHandler;
import com.bbn.openmap.MouseDelegator;
import com.bbn.openmap.event.AbstractMouseMode;
import com.bbn.openmap.event.SelectMouseMode;
import com.bbn.openmap.layer.GraticuleLayer;
import com.bbn.openmap.layer.shape.ShapeLayer;
import com.bbn.openmap.proj.Projection;
import java.awt.Color;
import java.awt.Toolkit;
import java.util.Properties;
import javax.swing.JComboBox;
import javax.swing.JPanel;

/**
 *
 * @author SIK - PTIK, BPPT
 */
public final class OMMapPanel extends BufferedLayerMapBean {

    /*atribut-atribut kelas OMMapPanel*/
        private MapHandler mapHandler;                            //untuk menangani panel peta
        private LayerHandler layerHandler;                        //untuk menangani layer-layer yang berada diatas panel peta

        private LatLonPoint centerLatLon;                           //titik tengah dari panel peta yang didasarkan pada latitude dan longitude

        private Color backgroundColor = new Color(0,100,100);       //warna latar dari peta

        private AbstractMouseMode mouseMode;                        //menangani penggunaan mouse pada peta

        private Layer mapLayer = indonesiaLayer();                  //layer peta
        private GraticuleLayer gratLayer = new GraticuleLayer();    //layer untuk garis lintang dan garis bujur
        private RadarLayer radarLayer;                              //layer radar
        private FlightLayer flightLayer;                            //layer pesawat
        private FixesLayer fixesLayer = new FixesLayer();           //layer fixes
        private AirwaysLayer airwaysLayer = new AirwaysLayer();     //layer Airways
        private AirportsLayer airportLayer = new AirportsLayer();   //layer Airports
        private ControlLayer controlLayer;                          //layer Control

        private String ScreenTitle;                                 //Title of main screen

    /**
     * Constructor - user defined constructor, no default constructor
     * @param screenTitle judul dari jendela utama
     */
        public OMMapPanel(String screenTitle)
        {
            /** Set screen title **/
            ScreenTitle = screenTitle;
            //menghitung latitude dan longitude dari radar
            String[] latitude = GlobalEnvVars.latRadar;
            String[] longitude = GlobalEnvVars.lonRadar;
            float centerLatitude = 0.0f;
            float centerLongitude = 0.0f;
            try{
                int latDeg = Integer.parseInt(latitude[0]);
                int latMin = Integer.parseInt(latitude[1]);
                float latSec = Float.parseFloat(latitude[2]);
                int latSign = latitude[3].charAt(0) == 'N' ? 1 : -1;
                centerLatitude = latSign * (latDeg + (latMin / 60.0f) + (latSec / 3600.0f));
                int lonDeg = Integer.parseInt(longitude[0]);
                int lonMin = Integer.parseInt(longitude[1]);
                float lonSec = Float.parseFloat(longitude[2]);
                int lonSign = longitude[3].charAt(0) == 'E' ? 1 : -1;
                centerLongitude = lonSign * (lonDeg + (lonMin / 60.0f) + (lonSec / 3600.0f));
            }catch(NumberFormatException e){
                centerLatitude = -2.0f;
                centerLongitude = 118.0f;
            }catch(Exception exp){
                centerLatitude = -2.0f;
                centerLongitude = 118.0f;
            }
            this.centerLatLon = new LatLonPoint(centerLatitude, centerLongitude); //center dari peta = center dari radar

            /*** Map Handler ***/
            this.mapHandler = getMapHandler(); //jika belum ada, dibuat terlebih dahulu. jika sudah pernah ada, diambil
            this.mapHandler.add(this); //untuk menambahkan objek pada mapHandler

            /*** Map ***/
            suppressCopyright = true;
            setCenter(this.centerLatLon);
            setBackground(this.backgroundColor);
            setScale(GlobalEnvVars.maxScale * 0.25f);

                //*** Graticule layer ***/
                this.gratLayer.setVisible(true);

                //*** Radar layer ***/
                this.radarLayer = new RadarLayer(
                    this,
                    Integer.parseInt(GlobalEnvVars.latRadar[0]),
                    Integer.parseInt(GlobalEnvVars.latRadar[1]),
                    Float.parseFloat(GlobalEnvVars.latRadar[2]),
                    GlobalEnvVars.latRadar[3].charAt(0),
                    Integer.parseInt(GlobalEnvVars.lonRadar[0]),
                    Integer.parseInt(GlobalEnvVars.lonRadar[1]),
                    Float.parseFloat(GlobalEnvVars.lonRadar[2]),
                    GlobalEnvVars.lonRadar[3].charAt(0)
                );

            /*** Layer Handler ***/
            this.layerHandler = new LayerHandler();
            this.layerHandler.addLayer(this.mapLayer);
            this.layerHandler.addLayer(this.gratLayer);
            this.layerHandler.addLayer(this.radarLayer);
            this.layerHandler.addLayer(this.fixesLayer);
            this.layerHandler.addLayer(this.airwaysLayer);
            this.layerHandler.addLayer(this.airportLayer);
            this.mapHandler.add(this.layerHandler);

            /*** mouse mode ***/
            this.mapHandler.add(new MouseDelegator());
            this.mouseMode = new SelectMouseMode();
            setMouseMode(this.mouseMode);
        }

    /* getter */
        /**
         * mengembalikan nilai dari atribut radarLayer
         * @return radar layer
         */
        public RadarLayer getRadarLayer()
            {return this.radarLayer;}

        /**
         * mengembalikan nilai dari atribut FlightLayer
         * @return flight layer
         */
        public FlightLayer getFlightLayer()
            {return this.flightLayer;}

        /**
         * mengembalikan skala peta saat ini
         * @return skala dari peta
         */
        public float getCurrentScale()
        {
            Projection proj = getProjection();
            return proj.getScale();
        }

    /* setter */
        /**
         * mengubah projection menjadi skala baru agar tampilan layar yang terlihat ketika opsi elevation view dipilih tidak berubah
         * @param scale float yang menyatakan skala dari projection saat ini
         * @param cb JComboBox
         */
        public void setBenyengScale(float scale, JComboBox cb)
        {
            int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
            float tempScale = scale * ((float)screenHeight / (float)(screenHeight - GlobalEnvVars.chartHeight));
            this.setCurrentScale(tempScale, cb, true);
        }

        /**
         * mengubah projection menjadi skala baru agar tampilan layar yang terlihat ketika opsi elevation view tidak dipilih tidak berubah
         * @param scale float yang menyatakan skala dari projection saat ini
         * @param cb JComboBox
         */
        public void setUnBenyengScale(float scale, JComboBox cb)
        {
            int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
            float tempScale = scale / ((float)screenHeight / (float)(screenHeight - GlobalEnvVars.chartHeight));
            this.setCurrentScale(tempScale, cb, false);
        }

        /**
         * mencek nilai dari scale dan mengubah skala dari peta secara global
         * @param scale nilai dari skala peta
         * @param cb combo box zoom untuk diset nilainya
         * @param drawChart bila menggambarkan elevation view
         */
        public void setCurrentScale(float scale, JComboBox cb, boolean drawChart)
        {
            Projection proj = getProjection();

            int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
            float tempScale = GlobalEnvVars.maxScale * ((float)screenHeight / (float)(screenHeight - GlobalEnvVars.chartHeight));

            if (! drawChart)
            {
                if (scale > GlobalEnvVars.maxScale)
                    scale = GlobalEnvVars.maxScale;
            }
            else
            {
                if (scale > tempScale)
                    scale = tempScale;
            }

            if (scale < GlobalEnvVars.minScale)
                scale = GlobalEnvVars.minScale;

            float temp = (((drawChart ? tempScale : GlobalEnvVars.maxScale)-scale)/4975000*100);
            if (temp >= 1f)
                cb.setSelectedItem((int)temp+"%");
            else
            {
                String str = String.format("%.2f", temp);
                cb.setSelectedItem(str+"%");
            }

            setScale(scale);
            projectionSupport.fireProjectionChanged(proj);
            purgeAndNotifyRemovedLayers();
        }

        /**
         * memanggil method setCurrentScale
         * @param scale nilai dari skala peta
         * @param cb combo box zoom untuk diset nilainya
         */
        public void setCurrentScale(float scale, JComboBox cb)
            {this.setCurrentScale(scale, cb, false);}

        /**
         * men-set mouseMode sesuai dengan parameter yang diberikan
         * @param mouseMode mode tetikus yang akan di-set
         */
        public void setMouseMode(AbstractMouseMode mouseMode)
        {
            //untuk men-set mouse mode misal panMouseMode
            if (this.mapHandler == null)
                return;

            if (this.mouseMode!= null)
                this.mapHandler.remove(this.mouseMode);

            this.mouseMode = mouseMode;

            this.mapHandler.add(this.mouseMode);
            removeMouseWheelListener(this.mouseMode); //menghilangkan mouse wheel
        }

        /**
         *  skala peta diubah menjadi skala terbesar dan titik tengah peta diubah sehingga titik tengah radar berada ditengah dari jendela aplikasi
         */
        public void setCenterAndFit()
        {
            setScale(GlobalEnvVars.maxScale);
            setCenter(this.centerLatLon);
        }

    /* method - method lain yang dimiliki oleh kelas OMMapPanel */
        private MapHandler getMapHandler()
        {
            if (mapHandler == null)
                mapHandler = new MapHandler();

            return mapHandler;
        }

        private Layer indonesiaLayer()
        {
            //membuat gambar peta indonesia
            ShapeLayer shapeLayer = new ShapeLayer();

            Properties shapeLayerProp = new Properties();
            shapeLayerProp.put("prettyName", "Indonesia Provinces");
            shapeLayerProp.put("lineColor","C0C0C0");
            shapeLayerProp.put("shapeFile","data/shape/ind_provinces.shp");
            shapeLayer.setProperties(shapeLayerProp);

            return shapeLayer;
        }

        //add and remove layer
        //<editor-fold defaultstate="collapsed" desc="add and remove">
        /**
         * graticule layer dihilangkan
         */
        public void removeGratLayer()
            {this.gratLayer.setVisible(false);}

        /**
         * graticule layer dimunculkan
         */
        public void addGratLayer()
            {this.gratLayer.setVisible(true);}

        /**
         * radar layer dihilangkan
         */
        public void removeRadarLayer()
            {this.radarLayer.setVisible(false);}

        /**
         * radar layer dimunculkan
         */
        public void addRadarLayer()
            {this.radarLayer.setVisible(true);}

        /**
         * flight layer dihapus dari layerHandler
         */
        public void removeFlightLayer()
            {this.layerHandler.removeLayer(flightLayer);}

        /**
         * flight layer ditambahkan pada mapHandler
         * @param bottomPanel panel untuk menampilkan elevationView
         * @param flightPlanList list dari flightPlan
         */
        public void addFlightLayer(JPanel bottomPanel, FlightPlanList flightPlanList)
        {
            this.flightLayer = new FlightLayer(this, bottomPanel, ScreenTitle, flightPlanList);
            this.mapHandler.add(flightLayer);
        }

        /**
         * fixes layer dihilangkan
         */
        public void removeFixesLayer()
            {this.fixesLayer.setVisible(false);}

        /**
         * fixes layer dimunculkan
         */
        public void addFixesLayer()
            {this.fixesLayer.setVisible(true);}

        /**
         * fixes layer diupdate
         */
        public void updateFixesLayer(boolean updateFixes, boolean updateNavaids)
            {this.fixesLayer.update(updateFixes, updateNavaids);}

        /**
         * airways layer dihilangkan
         */
        public void removeAirwaysLayer()
            {this.airwaysLayer.setVisible(false);}

        /**
         * airways layer dimunculkan
         */
        public void addAirwaysLayer()
            {this.airwaysLayer.setVisible(true);}

        /**
         * airways layer diupdate
         */
        public void updateAirwaysLayer()
            {this.airwaysLayer.update();}

        /**
         * map layer dihilangkan
         */
        public void removeMapLayer()
            {this.mapLayer.setVisible(false);}

        /**
         * map layer dimunculkan
         */
        public void addMapLayer()
            {this.mapLayer.setVisible(true);}

        /**
         * airport layer dihilangkan
         */
        public void removeAirportLayer()
            {this.airportLayer.setVisible(false);}

        /**
         * airport layer dimunculkan
         */
        public void addAirportLayer()
            {this.airportLayer.setVisible(true);}

        /**
         * airport layer diupdate
         */
        public void updateAirportLayer()
            {this.airportLayer.update();}

        /**
         * control layer dihapus dari layerHandler
         */
        public void removeControlLayer()
            {this.layerHandler.removeLayer(controlLayer);}

        /**
         * control layer ditambahkan pada layerHandler
         */
        public void addControlLayer()
        {
            this.controlLayer = new ControlLayer(ScreenTitle);
            this.layerHandler.addLayer(controlLayer);
        }
        //</editor-fold>
}